home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Mac OS SDK / Dev.CD Jul 99 SDK1.toast / Development Kits / Mac OS / Apple Guide / Engineering / APISample / APISampleCW / Source / UDocMo.cp < prev    next >
Encoding:
Text File  |  1994-05-26  |  28.9 KB  |  1,122 lines  |  [TEXT/MPS ]

  1. // Copyright ©1994 Apple Computer, Inc.
  2. // Author: John Powers
  3. // Date:   05-Mar-94
  4.  
  5. // UDocMo.cp
  6. // This file contains the documents and the objects that go
  7. // into the document window.
  8.  
  9. #ifndef __UDOCMO__
  10.     #include "UDocMo.h"
  11. #endif
  12.  
  13. extern Boolean gAGuideAvailable;
  14.  
  15. // Segment
  16.  
  17. #pragma segment Main
  18.  
  19. // ------------------------------------------------------------------------
  20. // TDocArt::DrawProc
  21. // Called by DeviceLoop.
  22. // A static function.  Must be in a resident segment, locked and unpurgeable.
  23. // Because it's static, it cannot access object member variables directly.
  24. // We use the document window passed in userData to access its variables.
  25. pascal void
  26. TDocArt::DrawProc(short depth, short /*deviceFlags*/,
  27.                                         GDHandle hTargetDevice,
  28.                                         long userData)
  29. {
  30.             // Get the document window from userData.
  31.     TDocArt* theDocObject = (TDocArt*) userData;
  32.             // Use depth of 1 if we have a computer without CQD.
  33.     depth = (hTargetDevice==NULL)?1:depth;
  34.             // Draw our objects.
  35.     for(short i=0; i<theDocObject->fArtCnt; i++)
  36.         ((TArt**)(*theDocObject->fhArt))[i]->Draw(depth);
  37. };
  38.  
  39. // Segment
  40.  
  41. #pragma segment MoG1
  42.  
  43. // =========================================================================
  44. // TDocArt : TDoc : TDocument
  45. // ------------------------------------------------------------------------
  46. // TDocArt::TDocArt
  47. // Document window constructor.
  48. // Creates the window contents (TArt objects).
  49. TDocArt::TDocArt(short resID) : TDoc(resID)
  50. {
  51.     this->fArtResId = 0;
  52.     this->fArtCnt = 0;
  53.     this->fIsCollision = false;
  54.     this->fCollisionEvent = 0;
  55.     this->fWantReset = false;
  56.     this->fWantShuffle = false;
  57.     this->fWantCollision = false;
  58.     this->fhArt = nil;
  59. }
  60.  
  61. // ------------------------------------------------------------------------
  62. // TDocArt::~TDocArt
  63. // Document window destructor.
  64. // Deletes the window contents (TArt objects).
  65. TDocArt::~TDocArt()
  66. {
  67.     if(this->fArtCnt)
  68.     {
  69.         for(short i=0; i<this->fArtCnt; i++)
  70.             delete ((TArt**)(*this->fhArt))[i];
  71.         DisposeHandle(this->fhArt);
  72.     }
  73.     if(this->fOffScreen)
  74.     {
  75.         delete this->fOffScreen;
  76.     }
  77. }
  78.  
  79. // ------------------------------------------------------------------------
  80. // TDocArt::DoContent
  81. // The localMouse is in the content portion of the window.
  82. // Check to see if it's on any art objects.
  83. void
  84. TDocArt::DoContent(EventRecord* pEvent)
  85. {
  86.     Rect    drawRect;
  87.     TArt*    artObj;
  88.     Point localMouse = pEvent->where;
  89.     GlobalToLocal(&localMouse);
  90.     for(short i=0; i<this->fArtCnt; i++)
  91.     {
  92.         artObj = ((TArt**)(*this->fhArt))[i];
  93.         artObj->GetDrawRect(&drawRect);
  94.         if(PtInRect(localMouse, &drawRect))
  95.         {
  96.             if(this->IsThisKeyDown(kCommandKey))
  97.             {
  98.                     // Command key down.
  99.                     // Startup the guide topic for this art object.
  100.                 if(gAGuideAvailable)
  101.                 {
  102.                         // Get preset guide database file from app.
  103.                     FSSpec fileSpec;
  104.                     this->fApp->GetFile(fileSpec);
  105.                     if(fileSpec.name[0]>0)
  106.                     {
  107.                         SetCursor(*GetCursor(watchCursor));
  108.                             // Open database.
  109.                         AGRefNum refNum;
  110.                         AlertIfError(AGOpenWithSequence(&fileSpec,
  111.                                             0, nil,
  112.                                             artObj->GetSequenceID(),
  113.                                             &refNum));
  114.                             // Set refNum for app.
  115.                         this->fApp->SetRefNum(refNum);
  116.                         SetCursor(&qd.arrow);
  117.                     }
  118.                 }
  119.             }
  120.             else if(artObj->IsMoveable())
  121.             {
  122.                     // Mouse down in our art and no key, track it.
  123.                 this->DragArt(artObj);
  124.             }
  125.                 // No need to check other art objects.
  126.             break;
  127.         }
  128.     }
  129.     if(this->fIsCollision)
  130.     {
  131.             // There was a collision, send the event if it exists.
  132.         if(gAGuideAvailable && this->fCollisionEvent)
  133.         {
  134.             AGRefNum refNum;
  135.             this->fApp->GetRefNum(refNum);
  136.             AGGeneral(refNum, this->fCollisionEvent);
  137.         }
  138.             // Reset collision flag so that we don't keep sending
  139.             // the event every time we click in the window.
  140.         this->fIsCollision = false;
  141.     }
  142. }
  143.  
  144. // ------------------------------------------------------------------------
  145. // TDocArt::DoIdle
  146. // Do any action required during the idle processing.
  147. //
  148. void
  149. TDocArt::DoIdle()
  150. {
  151.     if(this->fWantReset)
  152.     {
  153.         this->Reset();
  154.         this->fWantReset = false;
  155.     }
  156.     if(this->fWantShuffle)
  157.     {
  158.         this->Shuffle();
  159.         this->fWantShuffle = false;
  160.     }
  161. }
  162.  
  163. // ------------------------------------------------------------------------
  164. // TDocArt::DragArt
  165. // Track the mouseDown by dragging the art object.
  166. // The art object is not allowed to overlap another art object.
  167. void
  168. TDocArt::DragArt(TArt* theArt)
  169. {
  170.     Rect    drawRect;
  171.     Rect    eraseRectV;
  172.     Rect    eraseRectH;
  173.     Point    oldLoc;
  174.     Point    newLoc;
  175.     short    deltaV;
  176.     short    deltaH;
  177.         // Get a starting point for the mouseDown location.
  178.     GetMouse(&oldLoc);
  179.         // We may have been Coach-marked, the mouse-down
  180.         // will erase us along with the Coach mark.
  181.         // Let's refresh ourselves before moving.
  182.     theArt->Draw();
  183.     theArt->GetDrawRect(&drawRect);
  184.         // Save current window "picture" off screen.
  185.     this->DrawOff(theArt);
  186.         // Track mouse.
  187.     do
  188.     {
  189.         GetMouse(&newLoc);
  190.         if(PtInRect(newLoc, &drawRect)
  191.             && (newLoc.v!=oldLoc.v || newLoc.h!=oldLoc.h))
  192.         {
  193.                 // The mouse has moved, move the art.
  194.             deltaV = newLoc.v - oldLoc.v;
  195.             deltaH = newLoc.h - oldLoc.h;
  196.                 // Save the current location.
  197.             eraseRectV = eraseRectH = drawRect;
  198.                 // Proposed rect for art object.
  199.             OffsetRect(&drawRect, deltaH, deltaV);
  200.                 // Cannot go outside of window boundaries
  201.             if(this->IsOutsideWindow(&drawRect))
  202.             {
  203.                     // Set drawRect to current position.
  204.                 theArt->GetDrawRect(&drawRect);
  205.             }
  206.                 // Move if it doesn't overlap with another art object.
  207.             else if(this->IsCollision(theArt, &drawRect))
  208.             {
  209.                     // Oops, a collision; don't move.
  210.                 this->fIsCollision = true;
  211.                     // Set drawRect to current position.
  212.                 theArt->GetDrawRect(&drawRect);
  213.                     // Avoid "springing" effect.
  214.                 oldLoc = newLoc;
  215.             }
  216.             else
  217.             {
  218.                     // No collision, move.
  219.                 this->fIsCollision = false;
  220.                     // Sometimes we move more than one pixel.
  221.                     // Erase the area left behind.
  222.                 if(deltaV>0)
  223.                 {
  224.                         // Moving down.
  225.                     eraseRectV.bottom = eraseRectV.top+deltaV;
  226.                     this->fOffScreen->CopyOffToOn(eraseRectV);
  227.                 }
  228.                 else if(deltaV<0)
  229.                 {
  230.                         // Moving up.
  231.                     eraseRectV.top = eraseRectV.bottom+deltaV;
  232.                     this->fOffScreen->CopyOffToOn(eraseRectV);
  233.                 }
  234.                 if(deltaH>0)
  235.                 {
  236.                         // Moving to the right.
  237.                     eraseRectH.right = eraseRectH.left+deltaH;
  238.                     this->fOffScreen->CopyOffToOn(eraseRectH);
  239.                 }
  240.                 else if(deltaH<0)
  241.                 {
  242.                         // Moving to the left.
  243.                     eraseRectH.left = eraseRectH.right+deltaH;
  244.                     this->fOffScreen->CopyOffToOn(eraseRectH);
  245.                 }
  246.                     // Set new rect and redraw.
  247.                 theArt->SetDrawRect(&drawRect);
  248.                 theArt->Draw();
  249.                 oldLoc = newLoc;
  250.             }
  251.         }
  252.     }
  253.     while (StillDown());
  254. }
  255.  
  256. // ------------------------------------------------------------------------
  257. // TDocArt::Draw
  258. // Document window.
  259. // Within BeginUpdate/EndUpdate.
  260. //
  261. // We set the port because the port defaults to the frontmost window.
  262. // We may not be the frontmost window when the update occurs.
  263. //
  264. void
  265. TDocArt::Draw()
  266. {
  267.             // Setup and do DeviceLoop drawing.
  268.             // Pass the document window in userData.
  269.     long            userData=(long)this;
  270.     DeviceLoopFlags    flags=0;
  271.     SetPort(this->fDocWindow);
  272.     DeviceLoop(this->fDocWindow->visRgn,
  273.         NewDeviceLoopDrawingProc(TDocArt::DrawProc), userData, flags);
  274. };
  275.  
  276. // ------------------------------------------------------------------------
  277. // TDocArt::DrawOff
  278. // Draw window contents to off-screen port.
  279. // Don't draw exceptArt (can be nil).
  280. //
  281. void
  282. TDocArt::DrawOff(TArt* exceptArt)
  283. {
  284.     TArt*    theArt;
  285.             // Prepare off-screen world for drawing.
  286.     this->fOffScreen->PrepareForDrawing();
  287.             // Draw our objects in the off-screen port.
  288.     for(short i=0; i<this->fArtCnt; i++)
  289.     {
  290.         theArt = ((TArt**)(*this->fhArt))[i];
  291.         if(theArt!=exceptArt)
  292.         {
  293.             theArt->Draw();
  294.         }
  295.     }
  296.             // Finished drawing in off-screen world.
  297.     this->fOffScreen->DoneDrawing();
  298. };
  299.  
  300. // ------------------------------------------------------------------------
  301. // TDocArt::GetLocation
  302. // Get the Rect of the named object.
  303. // Return true if the object is found.
  304. //
  305. // If two names, separated by a dash (-), are given,
  306. // the union of the named objects will be returned.
  307. //
  308. Boolean
  309. TDocArt::GetLocation(Ptr pNameIn, Rect* pRect)
  310. {
  311.     Boolean    result=true;
  312.     char    pNameLocal[64];
  313.     Ptr        pName1=pNameLocal;
  314.     Ptr        pName2;
  315.     
  316.             // Split pNameIn into pName1 and pName2.
  317.  
  318.             // Copy first name to pNameLoc (pName1).
  319.     while(*pNameIn && *pNameIn!='-')
  320.         *pName1++ = *pNameIn++;
  321.             // Set terminator for first name at delimiter.
  322.     *pName1 = 0;
  323.             // Reset first name to the beginning.
  324.     pName1 = pNameLocal;
  325.             // If delimiter, then set pName2 to second name.
  326.             // Otherwise, set pName2 to point to null.
  327.     if(*pNameIn)
  328.         pName2 = pNameIn+1;
  329.     else
  330.         pName2 = pNameIn;
  331.  
  332.             // Compare first name with known objects.
  333.  
  334.     char    artName[32];
  335.     Rect    rect1;
  336.     Rect    rect2;
  337.     Boolean    found1=false;
  338.     Boolean    found2=false;
  339.  
  340.     for(short i=0; i<this->fArtCnt; i++)
  341.     {
  342.             // Get the name of the i-th art object.
  343.         ((TArt**)(*this->fhArt))[i]->GetName(artName);
  344.             // See if it matches the first name.
  345.         if(*pName1 && !found1)
  346.         {
  347.             if(relstring(pName1, artName, kNotCaseSens, kNotDiacSens))
  348.             {
  349.                 ((TArt**)(*this->fhArt))[i]->GetDrawRect(&rect1);
  350.                 found1 = true;
  351.             }
  352.         }
  353.             // See if it matches the second name.
  354.         if(*pName2 && !found2)
  355.         {
  356.             if(relstring(pName2, artName, kNotCaseSens, kNotDiacSens))
  357.             {
  358.                 ((TArt**)(*this->fhArt))[i]->GetDrawRect(&rect2);
  359.                 found2 = true;
  360.             }
  361.         }
  362.     }
  363.             // Form union if both names found.
  364.     if(found1 && found2)
  365.         UnionRect(&rect1, &rect2, pRect);
  366.     else if(found1)
  367.         *pRect = rect1;
  368.     else if(found2)
  369.         *pRect = rect2;
  370.     else
  371.         result = false;
  372.  
  373.     return result;
  374. };
  375.  
  376. // ------------------------------------------------------------------------
  377. // TDocArt::Init
  378. // Document window initialization.
  379. // Creates the window contents (TArt objects).
  380. // The art objects are linked to the window
  381. // by sharing the same resource ID.
  382. // The art object data is set in the LoadArt function.
  383. // We separate the functions so that LoadArt
  384. // can be used for Init and for resetting the objects.
  385. // The window pointer is set in the document initialization.
  386. // Return any error.
  387. //
  388. OSErr
  389. TDocArt::Init(short resID)
  390. {
  391.     OSErr    err=noErr;
  392.     TArt*    artObj;
  393.         // Save our resource id (for resetting.)
  394.     this->fArtResId = resID;
  395.         // Clear our member variables.
  396.     this->fArtCnt = 0;
  397.     this->fhArt = nil;
  398.         // Get the list of art objects.
  399.         // Use local variables for efficiency.
  400.     Handle hArt = GetResource(kResArtObjects, this->fArtResId);
  401.     if(hArt)
  402.     {
  403.             // Better lock this baby down or it will move.
  404.         HLock(hArt);
  405.             // Get the number of art objects.
  406.         ArtListPtr pArtList = (ArtListPtr) *hArt;
  407.         short artCnt = pArtList->artCnt;
  408.             // Get some memory to hold these babies.
  409.         Handle hArtList = NewHandle(artCnt*sizeof(ArtType));
  410.         if(hArtList)
  411.         {
  412.                 // Instantiate each art object and add to list.
  413.             for(short i=0; i<artCnt; i++)
  414.             {
  415.                 artObj = new TArt;
  416.                 ((TArt**)(*hArtList))[i] = artObj;
  417.             }
  418.                 // All okay, update member variables.
  419.             this->fhArt = hArtList;
  420.             this->fArtCnt = artCnt;
  421.                 // Load the art objects.
  422.             this->LoadArt();
  423.         }
  424.         HUnlock(hArt);
  425.     }
  426.     this->fOffScreen = new TBitMapColor;
  427.     if(this->fOffScreen)
  428.         err = this->fOffScreen->Init();
  429.     return err;
  430. }
  431.  
  432. // ------------------------------------------------------------------------
  433. // TDocArt::IsCollision
  434. //
  435. // Tests to see if the proposed rectangle for theArt intersects with any
  436. // of the remaining art objects.  Returns true or false.
  437. // They must be on the same layer to collide.
  438. //
  439. Boolean
  440. TDocArt::IsCollision(TArt* theArt, Rect* proposedArtRect)
  441. {
  442.     Rect    testRect;
  443.     Rect    dstRect;
  444.     TArt*    theOtherArt;
  445.     for(short i=0; i<this->fArtCnt; i++)
  446.     {
  447.         theOtherArt = ((TArt**)(*this->fhArt))[i];
  448.         if(theOtherArt!=theArt)
  449.         {
  450.             if(this->IsSameLayer(theArt, theOtherArt))
  451.             {
  452.                 theOtherArt->GetDrawRect(&testRect);
  453.                 if(SectRect(proposedArtRect, &testRect, &dstRect))
  454.                 {
  455.                     return true;
  456.                 }
  457.             }
  458.         }
  459.     }
  460.     return false;
  461. }
  462.  
  463. // ------------------------------------------------------------------------
  464. // TDocArt::IsOutsideWindow
  465. // Return true if any portion of the art object 
  466. // is outside of the window content area.
  467. //
  468. // Calculate the intersection of the proposedArtRect with the portRect.
  469. // If the proposedArtRect is entirely within the portRect, the
  470. // intersection will be equal to the proposedArtRect.
  471. // 
  472. Boolean
  473. TDocArt::IsOutsideWindow(Rect* proposedArtRect)
  474. {
  475.     Rect insideRect;
  476.     SectRect(proposedArtRect, &this->fDocWindow->portRect, &insideRect);
  477.     return !EqualRect(proposedArtRect, &insideRect);
  478. }
  479.  
  480. // ------------------------------------------------------------------------
  481. // TDocArt::IsSameLayer
  482. // Return true if the art objects are at the same layer.
  483. Boolean
  484. TDocArt::IsSameLayer(TArt* theArt, TArt* theOtherArt)
  485. {
  486.     return theArt->GetLayer()==theOtherArt->GetLayer();
  487. }
  488.  
  489. // ------------------------------------------------------------------------
  490. // TDocArt::Reset
  491. // Reset the window.
  492. // In this case, we erase the window and redraw its contents.
  493. //
  494. void
  495. TDocArt::Reset()
  496. {
  497.     this->Erase();
  498.     this->LoadArt();
  499.     this->Invalidate();
  500. }
  501.  
  502. // ------------------------------------------------------------------------
  503. // TDocArt::LoadArt
  504. // Art object initialization.
  505. // The memory was allocated in the Init function.
  506. // We separate the functions so that LoadArt
  507. // can be used for Init and for resetting the objects.
  508. void
  509. TDocArt::LoadArt()
  510. {
  511.         // Get the list of art objects.
  512.     Handle hArt = GetResource(kResArtObjects, this->fArtResId);
  513.     if(hArt)
  514.     {
  515.             // Better lock this baby down or it will move.
  516.         HLock(hArt);
  517.             // Get the number of art objects.
  518.         ArtListPtr pArtList = (ArtListPtr) *hArt;
  519.             // Instantiate each art object and add to list.
  520.         for(short i=0; i<this->fArtCnt; i++)
  521.         {
  522.             ((TArt**)(*this->fhArt))[i]->Init(pArtList->art[i]);
  523.         }
  524.         HUnlock(hArt);
  525.     }
  526. }
  527.  
  528. // ------------------------------------------------------------------------
  529. // TDocArt::Shuffle
  530. // Shuffle the location of the art objects.
  531. // We do this by swapping each of the objects
  532. // with another object selected at random.
  533. void
  534. TDocArt::Shuffle()
  535. {
  536.     short    randomNum;
  537.     short    iA;
  538.     short    iB;
  539.     TArt*    artA;
  540.     TArt*    artB;
  541.     if(this->fArtCnt<=0)
  542.         return;
  543.             // Use this->LoadArt() to return all art to its normal location.
  544.     this->Erase();
  545.             // Seed random number generator.
  546.     GetDateTime((unsigned long *)&qd.randSeed);
  547.         // Step through each art object.
  548.     for(iA=0; iA<this->fArtCnt; iA++)
  549.     {
  550.         artA = ((TArt**)(*this->fhArt))[iA];
  551.             // Positive index from 0 to this->fArtCnt-1.
  552.         randomNum = Random();
  553.         randomNum = (randomNum<0)?-randomNum:randomNum;
  554.         iB = randomNum/(32767/this->fArtCnt);
  555. #if __DebugShuffle__
  556.         Str255 msgStr;
  557.         NumToString(iB, msgStr);
  558.         if(iB<0)
  559.         {
  560.             PLstrcat(msgStr, "\p is less than 0.");
  561.             DebugStr(msgStr);
  562.             iB = 0;
  563.         }
  564.         else if(iB>=this->fArtCnt)
  565.         {
  566.             Str255 numStr;
  567.             PLstrcat(msgStr, "\p is equal to or greater than ");
  568.             NumToString(this->fArtCnt, numStr);
  569.             PLstrcat(msgStr, numStr);
  570.             DebugStr(msgStr);
  571.             iB = this->fArtCnt-1;
  572.         }
  573. #endif
  574.         artB = ((TArt**)(*this->fhArt))[iB];
  575.         if(artA!=artB)
  576.         {
  577.                 // Swap locations.
  578.             Rect drawRectA;
  579.             Rect drawRectB;
  580.             artA->GetDrawRect(&drawRectA);
  581.             artB->GetDrawRect(&drawRectB);
  582.             artA->SetDrawRect(&drawRectB);
  583.             artB->SetDrawRect(&drawRectA);
  584.         }
  585.     }
  586.             // Let's draw all the art in its new location.
  587.     this->Invalidate();
  588. }
  589.  
  590. // =========================================================================
  591. // TDocFB : TDoc : TDocument
  592. // ------------------------------------------------------------------------
  593. // TDocFB::TDocFB
  594. // Document window constructor.
  595. // This empty constructor passes the resID to TDoc.
  596. //
  597. TDocFB::TDocFB(short resID) : TDoc(resID)
  598. {
  599.     this->fhControl = nil;
  600. }
  601.  
  602. // ------------------------------------------------------------------------
  603. // TDocFB::~TDocFB
  604. // Document window destructor.
  605. //
  606. TDocFB::~TDocFB()
  607. {
  608.     if(this->fhControl!=nil)
  609.         DisposeControl(this->fhControl);
  610. }
  611.  
  612. // ------------------------------------------------------------------------
  613. // TDocFB::DoContent
  614. // The mouseDown is in the content portion of the window.
  615. // Check to see if it's on a control.
  616. //
  617. void
  618. TDocFB::DoContent(EventRecord* pEvent)
  619. {
  620.     ControlHandle    whichControl;
  621.     Point localMouse = pEvent->where;
  622.     GlobalToLocal(&localMouse);
  623.     short partCode = FindControl(localMouse, this->fDocWindow, &whichControl);
  624.     if(partCode!=0)
  625.     {
  626.         if(TrackControl(whichControl, localMouse, nil)==partCode)
  627.         {
  628.                 // The control was controlled.
  629.                 // Startup the preset database.
  630.             if(gAGuideAvailable)
  631.             {
  632.                     // Get preset guide database file from app.
  633.                 FSSpec fileSpec;
  634.                 this->fApp->GetFile(fileSpec);
  635.                 if(fileSpec.name[0]>0)
  636.                 {
  637.                     SetCursor(*GetCursor(watchCursor));
  638.                         // Open database.
  639.                     AGRefNum refNum;
  640.                     AlertIfError(AGOpen(&fileSpec, 0, nil, &refNum));
  641.                         // Set refNum for app.
  642.                     this->fApp->SetRefNum(refNum);
  643.                     SetCursor(&qd.arrow);
  644.                 }
  645.             }
  646.         }
  647.     }
  648. };
  649.  
  650. // ------------------------------------------------------------------------
  651. // TDocFB::Draw
  652. //
  653. // We set the port because the port defaults to the frontmost window.
  654. // We may not be the frontmost window when the update occurs.
  655. //
  656. void
  657. TDocFB::Draw()
  658. {
  659.     Str255 string;
  660.     SetPort(this->fDocWindow);
  661.     TextFont(monaco);
  662.     TextSize(9);
  663.     TextMode(patCopy);
  664.         // Context check
  665.     MoveTo(kLocH, kLocCCV);
  666.     GetIndString(string, kFeedbackStrId, kStrContext);
  667.     DrawString(string);
  668.     GetPen(&this->fLoc[dataCC]);
  669.         // Coach mark
  670.     MoveTo(kLocH, kLocCHV);
  671.     GetIndString(string, kFeedbackStrId, kStrCoach);
  672.     DrawString(string);
  673.     GetPen(&this->fLoc[dataCH]);
  674.         // Event
  675.     MoveTo(kLocH, kLocEVV);
  676.     GetIndString(string, kFeedbackStrId, kStrEvent);
  677.     DrawString(string);
  678.     GetPen(&this->fLoc[dataEV]);
  679.         // Miscellaneous
  680.     MoveTo(kLocH, kLocMSV);
  681.     GetIndString(string, kFeedbackStrId, kStrMisc);
  682.     DrawString(string);
  683.     GetPen(&this->fLoc[dataTP]);
  684.         // Control
  685.     DrawControls(this->fDocWindow);
  686. }
  687.  
  688. // ------------------------------------------------------------------------
  689. // TDocFB::DrawData
  690. //
  691. // We set the port because the port defaults to the frontmost window.
  692. // We may not be the frontmost window when the update occurs.
  693. //
  694. // The IM QuickDraw documentation is not clear on whether to
  695. // use PenMode or TextMode.  We are passing patCopy to draw
  696. // and patBic to erase in a TextMode procedure, not srcOr and srcBic
  697. // as the documentation would lead you to believe.  Nor does the
  698. // use of patCopy and patBic with PenMode work. Our usage works.
  699. //
  700. void
  701. TDocFB::DrawData(Str255 string, short mode, short whichData)
  702. {
  703.     SetPort(this->fDocWindow);
  704.     TextMode(mode);
  705.     MoveTo(this->fLoc[whichData].h, this->fLoc[whichData].v);
  706.     DrawString(string);
  707. }
  708.  
  709. // ------------------------------------------------------------------------
  710. // TDocFB::Init
  711. //
  712. OSErr
  713. TDocFB::Init()
  714. {
  715.     OSErr err=noErr;
  716.     this->fhControl = GetNewControl(kAssistantCntlID, this->fDocWindow);
  717.     if(this->fhControl)
  718.     {
  719.             // Center control.
  720.         short winWidth = this->fDocWindow->portRect.right
  721.                             - this->fDocWindow->portRect.left;
  722.         short ctrlWidth = (**this->fhControl).contrlRect.right
  723.                             - (**this->fhControl).contrlRect.left;
  724.         short ctrlLeft = (winWidth - ctrlWidth) / 2;
  725.         MoveControl(this->fhControl, ctrlLeft, kLocCTV);
  726.         ShowControl(this->fhControl);
  727.     }
  728.     else
  729.         err = kErrDocFBInitFailed;
  730.     return err;
  731. };
  732.  
  733. // =========================================================================
  734. // TArt
  735. // ------------------------------------------------------------------------
  736. // TArt::Draw
  737. // All art objects (PICT's) are drawn from here.
  738. // This is where we distinguish between B&W and color renderings
  739. // of TArt objects.  The B&W rendering has a resource ID that
  740. // is kBWOffset larger than its color counterpart.
  741. // If the function can't find one version, it will try the other.
  742. void
  743. TArt::Draw(short depth)
  744. {
  745.             // Don't draw empty art.
  746.     if(this->fArt.pictId==0)
  747.         return;
  748.     this->fLastDepth = depth;
  749.     PicHandle    hPict;
  750.     if(depth<8)
  751.     {
  752.             // Use B&W PICT.
  753.         hPict = (PicHandle) GetResource('PICT', this->fArt.pictId+kBWOffset);
  754.         if(!hPict)
  755.         {
  756.                 // No B&W PICT, try color (may really be B&W).
  757.             hPict = (PicHandle) GetResource('PICT', this->fArt.pictId);
  758.         }
  759.     }
  760.     else
  761.     {
  762.             // Use color PICT.
  763.         hPict = (PicHandle) GetResource('PICT', this->fArt.pictId);
  764.         if(!hPict)
  765.         {
  766.                 // No color PICT, try B&W.
  767.             hPict = (PicHandle) GetResource('PICT', this->fArt.pictId+kBWOffset);
  768.         }
  769.     }
  770.     if(hPict)
  771.     {
  772.             // We could have used the fDrawRect private member variable,
  773.             // but we'll use the access function here.
  774.         Rect theDrawRect;
  775.         this->GetDrawRect(&theDrawRect);
  776.         HLock((Handle) hPict);
  777.         DrawPicture(hPict, &theDrawRect);
  778.         HUnlock((Handle) hPict);
  779.     }
  780. };
  781.  
  782. // ------------------------------------------------------------------------
  783. // TArt::Draw
  784. // Draw at the depth used for the last call.
  785. void
  786. TArt::Draw()
  787. {
  788.     this->Draw(this->fLastDepth);
  789. }
  790.  
  791. // ------------------------------------------------------------------------
  792. void
  793. TArt::GetDrawRect(Rect* theRect)
  794. {
  795.     *theRect = this->fDrawRect;
  796. }
  797.  
  798. // ------------------------------------------------------------------------
  799. // TArt::GetName
  800. // Return the name of the art object by copying it to theName.
  801. void
  802. TArt::GetName(char* theName)
  803. {
  804.     char* pArtName=this->fArt.name;
  805.     while(*theName++=*pArtName++)
  806.         ;
  807. }
  808.  
  809. // ------------------------------------------------------------------------
  810. // TArt::Init
  811. // Initialize the art object.
  812. // Set it's PICT ID and drawing location.
  813. void
  814. TArt::Init(ArtType theArt)
  815. {
  816.         // Save art object description.
  817.     this->fArt = theArt;
  818.     this->fLastDepth = 1;
  819.     SetRect(&this->fDrawRect, 0, 0, 0, 0);
  820.         // Normalize PICT to desired drawing location.
  821.     PicHandle hPict = (PicHandle) GetResource('PICT', this->fArt.pictId);
  822.     if(hPict)
  823.     {
  824.                 // Get the original drawing rect.
  825.         this->fDrawRect = (**hPict).picFrame;
  826.                 // Normalize rect to 0,0 in case the artist didn't.
  827.         OffsetRect(&this->fDrawRect, -this->fDrawRect.left,
  828.                                         -this->fDrawRect.top);
  829.                 // Move rect to loc.
  830.         OffsetRect(&this->fDrawRect, this->fArt.locH, this->fArt.locV);
  831.     }
  832. };
  833.  
  834. // ------------------------------------------------------------------------
  835. void
  836. TArt::SetDrawRect(Rect* theRect)
  837. {
  838.     this->fDrawRect = *theRect;
  839. }
  840.  
  841. // =========================================================================
  842. // TBitMap
  843. // ------------------------------------------------------------------------
  844. TBitMap::TBitMap()                // constructor
  845. {
  846. };
  847.  
  848. // ------------------------------------------------------------------------
  849. TBitMap::~TBitMap()        // destructor
  850. {
  851. };
  852.  
  853. // =========================================================================
  854. // TBitMapBW-->TBitMap
  855. // ------------------------------------------------------------------------
  856. TBitMapBW::TBitMapBW()                // constructor
  857. {
  858.     this->fOffPort = nil;
  859. };
  860.  
  861. // ------------------------------------------------------------------------
  862. TBitMapBW::~TBitMapBW()        // destructor
  863. {
  864.     if(this->fOffPort)
  865.     {
  866.         ClosePort(this->fOffPort);
  867.         DisposPtr(this->fOffPort->portBits.baseAddr);
  868.         DisposPtr((Ptr)this->fOffPort);
  869.     }
  870. };
  871.  
  872. // ------------------------------------------------------------------------
  873. // TBitMapBW::CopyOffToOn
  874. // Copy all of off-screen port to on-screen port.
  875. void
  876. TBitMapBW::CopyOffToOn()
  877. {
  878.     this->CopyOffToOn(this->fOffRect);
  879. };
  880.  
  881. // ------------------------------------------------------------------------
  882. // TBitMapBW::CopyOffToOn
  883. // Copy a rect from off-screen port to on-screen port.
  884. void
  885. TBitMapBW::CopyOffToOn(Rect& rectToCopy)
  886. {
  887.     GrafPtr         onPort;
  888.     
  889.     GetPort(&onPort);
  890.     CopyBits(    &this->fOffPort->portBits,
  891.                 &onPort->portBits,
  892.                 &rectToCopy,
  893.                 &rectToCopy, srcCopy, nil);
  894. };
  895.  
  896. // ------------------------------------------------------------------------
  897. // TBitMapBW::CopyOnToOff
  898. // Copy all of on-screen port to off-screen port.
  899. void
  900. TBitMapBW::CopyOnToOff()
  901. {
  902.     this->CopyOnToOff(this->fOffRect);
  903. };
  904.  
  905. // ------------------------------------------------------------------------
  906. // TBitMapBW::CopyOnToOff
  907. // Copy a rect from on-screen port to off-screen port.
  908. void
  909. TBitMapBW::CopyOnToOff(Rect& rectToCopy)
  910. {
  911.     GrafPtr         onPort;
  912.     
  913.     GetPort(&onPort);
  914.     CopyBits(    &onPort->portBits,    
  915.                 &this->fOffPort->portBits,
  916.                 &rectToCopy,
  917.                 &rectToCopy, srcCopy, nil);
  918. };
  919.  
  920. // ------------------------------------------------------------------------
  921. // TBitMapBW::DoneDrawing
  922. void
  923. TBitMapBW::DoneDrawing()        
  924. {
  925.     SetPort(this->fSavedOnPort);
  926. }
  927.  
  928. // ------------------------------------------------------------------------
  929. // TBitMapBW::Init
  930. // Build bit map for an offscreen port equal to the current grafPort.
  931. OSErr
  932. TBitMapBW::Init()        
  933. {
  934.     OSErr        err;
  935.     Rect        offRect;
  936.     GrafPtr        onPort,
  937.                 newOffPort;
  938.  
  939.     GetPort(&onPort);
  940.             // Our off-screen rect exactly duplicates the on-screen rect.
  941.     offRect = onPort->portRect;
  942.             // Normalize off-screen rect.
  943.     OffsetRect(&offRect, -offRect.left, -offRect.top);
  944.     newOffPort = (GrafPtr) NewPtr(sizeof(GrafPort));
  945.     if((err=MemError())!=noErr)
  946.         return err;
  947.     OpenPort(newOffPort);
  948.     newOffPort->portRect = offRect;
  949.     newOffPort->portBits.bounds = offRect;
  950.     RectRgn(newOffPort->clipRgn, &offRect);
  951.     RectRgn(newOffPort->visRgn, &offRect);
  952.             // Rect is normalized so we only need to use its right and bottom.
  953.     newOffPort->portBits.rowBytes = ((offRect.right + 15) >> 4) << 1;
  954.     newOffPort->portBits.baseAddr = NewPtr(newOffPort->portBits.rowBytes * (long)offRect.bottom);
  955.     if((err=MemError())!=noErr) {
  956.         SetPort(onPort);
  957.         ClosePort(newOffPort);
  958.         DisposPtr((Ptr)newOffPort);
  959.         return err;
  960.         }
  961.             // Clear out new offScreen rect.
  962.     EraseRect(&offRect);
  963.             // Save key variables.
  964.     this->fOffRect = offRect;
  965.     this->fOffPort = newOffPort;
  966.             // Restore to screen port.
  967.     SetPort(onPort);
  968.     return noErr;
  969. };
  970.  
  971. // ------------------------------------------------------------------------
  972. // TBitMapBW::PrepareForDrawing
  973. // Set the port to this bit map and erase it.
  974. void
  975. TBitMapBW::PrepareForDrawing()        
  976. {
  977.     GetPort(&this->fSavedOnPort);
  978.     SetPort(this->fOffPort);
  979.     EraseRect(&this->fOffRect);
  980. }
  981.  
  982. // =========================================================================
  983. // TBitMapColor-->TBitMap
  984. // ------------------------------------------------------------------------
  985. TBitMapColor::TBitMapColor()        // constructor
  986. {
  987.     this->fOffGWorld = nil;
  988. };
  989.  
  990. // ------------------------------------------------------------------------
  991. TBitMapColor::~TBitMapColor()        // destructor
  992. {
  993.     if(this->fOffGWorld)
  994.     {
  995.         DisposeGWorld(this->fOffGWorld);
  996.     }
  997. };
  998.  
  999. // ------------------------------------------------------------------------
  1000. // TBitMapColor::CopyOffToOn
  1001. // Copy all of off-screen port to on-screen port.
  1002. void
  1003. TBitMapColor::CopyOffToOn()
  1004. {
  1005.     this->CopyOffToOn(this->fOffRect);
  1006. };
  1007.  
  1008. // ------------------------------------------------------------------------
  1009. // TBitMapColor::CopyOffToOn
  1010. // Copy a rect from off-screen port to on-screen port.
  1011. void
  1012. TBitMapColor::CopyOffToOn(Rect& rectToCopy)
  1013. {
  1014.     CGrafPtr         onPort;
  1015.     GDHandle        onDevice;
  1016.     
  1017.     GetGWorld(&onPort, &onDevice);
  1018.     PixMapHandle hOffPixMap = GetGWorldPixMap(this->fOffGWorld);
  1019.      LockPixels(hOffPixMap);
  1020.     CopyBits(    &**(BitMap**)hOffPixMap,    
  1021.                 &**(BitMap**)onPort->portPixMap,
  1022.                 &rectToCopy,
  1023.                 &rectToCopy,
  1024.                 srcCopy, nil);
  1025.     UnlockPixels(hOffPixMap);
  1026. };
  1027.  
  1028. // ------------------------------------------------------------------------
  1029. // TBitMapColor::CopyOnToOff
  1030. // Copy all of on-screen port to off-screen port.
  1031. void
  1032. TBitMapColor::CopyOnToOff()
  1033. {
  1034.     this->CopyOnToOff(this->fOffRect);
  1035. };
  1036.  
  1037. // ------------------------------------------------------------------------
  1038. // TBitMapColor::CopyOnToOff
  1039. // Copy a rect from on-screen port to off-screen port.
  1040. void
  1041. TBitMapColor::CopyOnToOff(Rect& rectToCopy)
  1042. {
  1043.     CGrafPtr         onPort;
  1044.     GDHandle        onDevice;
  1045.     
  1046.     GetGWorld(&onPort, &onDevice);
  1047.     PixMapHandle hOffPixMap = GetGWorldPixMap(this->fOffGWorld);
  1048.      LockPixels(hOffPixMap);
  1049.     CopyBits(    &**(BitMap**)onPort->portPixMap,    
  1050.                 &**(BitMap**)hOffPixMap,
  1051.                 &rectToCopy,
  1052.                 &rectToCopy,
  1053.                 srcCopy, nil);
  1054.     UnlockPixels(hOffPixMap);
  1055. };
  1056.  
  1057. // ------------------------------------------------------------------------
  1058. // TBitMapColor::DoneDrawing
  1059. void
  1060. TBitMapColor::DoneDrawing()        
  1061. {
  1062.     UnlockPixels(GetGWorldPixMap(this->fOffGWorld));
  1063.     SetGWorld(this->fSavedOnPort, this->fSavedOnDevice);
  1064. }
  1065.  
  1066. // ------------------------------------------------------------------------
  1067. // TBitMapColor::Init
  1068. // Build bit map for an offscreen port equal to the current grafPort.
  1069. OSErr
  1070. TBitMapColor::Init()    
  1071. {
  1072.     short            pixelDepth=8;
  1073.     RGBColor        myRGBColor;
  1074.     CGrafPtr         onPort;
  1075.     GDHandle        onDevice;
  1076.     GWorldPtr        offGWorld;
  1077.     Rect            offRect;
  1078.  
  1079.     GetGWorld(&onPort, &onDevice);
  1080.     offRect = onPort->portRect;
  1081.             // Normalize off-screen rect.
  1082.     OffsetRect(&offRect, -offRect.left, -offRect.top);
  1083.             // we have created a world
  1084.     OSErr err = NewGWorld(&offGWorld, pixelDepth, &offRect, nil, nil, 0);
  1085.     if(err!=noErr)
  1086.         return err;
  1087.             // Everything from here on is done off screen.
  1088.     SetGWorld(offGWorld, nil);
  1089.             // set the background color to white
  1090.     myRGBColor.red = 0xFFFF;
  1091.     myRGBColor.blue = 0xFFFF;
  1092.     myRGBColor.green = 0xFFFF;
  1093.     RGBBackColor(&myRGBColor);
  1094.             // set the foreground color to black
  1095.     myRGBColor.red = 0;
  1096.     myRGBColor.blue = 0;
  1097.     myRGBColor.green = 0;
  1098.     RGBForeColor(&myRGBColor);
  1099.             // Clear out new offScreen rect.
  1100.     EraseRect(&offRect);
  1101.             // Save key variables.
  1102.     this->fOffRect = offRect;
  1103.     this->fOffGWorld = offGWorld;
  1104.             // Restore to on-screen GWorld.
  1105.     SetGWorld(onPort, onDevice);
  1106.     return noErr;
  1107. };
  1108.  
  1109. // ------------------------------------------------------------------------
  1110. // TBitMapColor::PrepareForDrawing
  1111. // Set the port to this bit map and erase it.
  1112. void
  1113. TBitMapColor::PrepareForDrawing()        
  1114. {
  1115.     GetGWorld(&this->fSavedOnPort, &this->fSavedOnDevice);
  1116.     SetGWorld(this->fOffGWorld, nil);
  1117.         // We ignore any failure of LockPixels.
  1118.     (void) LockPixels(GetGWorldPixMap(this->fOffGWorld));
  1119.     EraseRect(&this->fOffRect);
  1120. }
  1121.  
  1122.